home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / AX25.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-06  |  31.7 KB  |  1,115 lines

  1. /*  Low level AX.25 code:
  2.  *  incoming frame processing (including digipeating)
  3.  *  IP encapsulation
  4.  *  digipeater routing
  5.  *
  6.  *  Copyright 1991 Phil Karn, KA9Q / 1991 Kevin Hil, G1EMM
  7.  */
  8. /* Mods by PA0GRI */
  9.  
  10. #include "global.h"
  11. #ifdef AX25
  12. #include "commands.h"
  13. #include "mbuf.h"
  14. #include "iface.h"
  15. #include "arp.h"
  16. #include "netrom.h"
  17. #include "trace.h"
  18. #include "pktdrvr.h"
  19.  
  20. #if !defined(_lint)
  21. static char rcsid[] OPTIONAL = "$Id: ax25.c,v 1.27 1997/09/07 00:31:16 root Exp root $";
  22. #endif
  23.  
  24. static int axsend (struct iface * iface, const char *dest, char *source,
  25.                int cmdrsp, int ctl, struct mbuf * data);
  26.  
  27. static void incCounter (struct iface *iface);
  28.                
  29. #ifdef AXIP
  30. static int axip_stop (struct iface * iface);
  31. static int axip_raw (struct iface * iface, struct mbuf * bp);
  32. #endif
  33.  
  34. #ifdef AUTOROUTE
  35. extern int ax25_check_corruption (struct ax25 * header);
  36. #endif /* AUTOROUTE */
  37.  
  38. extern int AXSmartRoute;
  39. #ifdef AXUI
  40. extern int Axui_sock;
  41. #endif
  42.  
  43. #ifdef NODECALL
  44. extern int NodeAlias, NodeNetrom;
  45. #endif
  46.  
  47.  
  48. /* List of AX.25 multicast addresses in network format (shifted ascii).
  49.  * Only the first entry is used for transmissions, but any incoming
  50.  * packet with any one of these destination addresses is recognized
  51.  * as a multicast
  52.  */
  53. /* NOTE: IF you CHANGE the order of these, also change the codes in ax25.h !!!
  54.  * mailfor.c, nr3, and ax25cmd.c depend on this to get broadcast addresses !!!
  55.  * 920306 - WG7J
  56.  */
  57. /*lint -save -e569 */
  58. char Ax25multi[][AXALEN] =
  59. {
  60.      {'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1},    /* QST */
  61.      {'N' << 1, 'O' << 1, 'D' << 1, 'E' << 1, 'S' << 1, ' ' << 1, '0' << 1},    /* NODES */
  62.      {'M' << 1, 'A' << 1, 'I' << 1, 'L' << 1, ' ' << 1, ' ' << 1, '0' << 1},    /* MAIL */
  63.      {'I' << 1, 'D' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1},    /* ID */
  64.      {'O' << 1, 'P' << 1, 'E' << 1, 'N' << 1, ' ' << 1, ' ' << 1, '0' << 1},    /* OPEN */
  65.      {'C' << 1, 'Q' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1},    /* CQ */
  66.      {'B' << 1, 'E' << 1, 'A' << 1, 'C' << 1, 'O' << 1, 'N' << 1, '0' << 1},    /* BEACON */
  67.      {'R' << 1, 'M' << 1, 'N' << 1, 'C' << 1, ' ' << 1, ' ' << 1, '0' << 1},    /* RMNC */
  68.      {'A' << 1, 'L' << 1, 'L' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1},    /* ALL */
  69.     {'\0'},
  70. };
  71.  
  72. char NOCALL[] = {'N' << 1, 'O' << 1, 'C' << 1, 'A' << 1, 'L' << 1, 'L' << 1, '0' << 1};
  73.  
  74. /*lint -restore */
  75.  
  76. char Mycall[AXALEN];
  77. char AXuser[AXALEN];
  78. char MyBBS[AXALEN];
  79. char Myalias[AXALEN];        /* the NETROM alias in 'call' form */
  80.  
  81. #ifdef NETROM
  82. char Nralias[ALEN + 1];        /* the NETROM alias in 'alias' form */
  83. #endif
  84.  
  85. #ifdef CONVERS
  86. char Ccall[AXALEN], Calias[AXALEN];
  87. #endif
  88.  
  89. #ifdef TTYCALL
  90. char Ttycall[AXALEN];
  91. #endif
  92.  
  93. #ifdef NODECALL
  94. char Nodecall[AXALEN];
  95. char Nodealias[AXALEN];
  96. #endif
  97.  
  98. #ifdef MBFWD
  99. extern char FWDCall[AXALEN];
  100. #endif
  101.  
  102. char Tcall[AXALEN];
  103. char Icall[AXALEN];
  104. char Ncall[AXALEN];
  105.  
  106. struct ax_route *Ax_routes;        /* Routing table header */
  107. struct ax_route *Ax_setups;    /* Routing table header for setting up connections */
  108. static int Ax_setups_counter = 0;
  109.  
  110. #ifdef AXIP
  111. uint32 *axipaddr;        /* table of IP addresses of AX.25 interfaces */
  112. int AXIPlinks = NAX25;
  113.  
  114. #ifdef PPP
  115. extern int16 fcstab[];    /* table used when calculating FCS */
  116. #else
  117. int16 fcstab[256] =
  118. {
  119.     0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
  120.     0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
  121.     0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
  122.     0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
  123.     0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
  124.     0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
  125.     0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
  126.     0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
  127.     0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
  128.     0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
  129.     0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
  130.     0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
  131.     0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
  132.     0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
  133.     0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
  134.     0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
  135.     0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
  136.     0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
  137.     0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
  138.     0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
  139.     0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
  140.     0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
  141.     0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
  142.     0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
  143.     0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
  144.     0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
  145.     0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
  146.     0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
  147.     0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
  148.     0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
  149.     0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
  150.     0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
  151. };
  152.  
  153. #endif
  154. #endif
  155.  
  156.  
  157. static void
  158. incCounter (struct iface *iface)
  159. {
  160.     /* update the counters for messages out */
  161.     if (iface)
  162.         iface->axcnt.msgout++;
  163. }
  164.  
  165.  
  166.  
  167. /* Send IP datagrams across an AX.25 link */
  168. int
  169. ax_send (struct mbuf *bp, struct iface *iface, uint32 gateway, int prec OPTIONAL,
  170.     int del, int tput OPTIONAL, int rel)
  171. {
  172. char *hw_addr;
  173. struct ax25_cb *axp;
  174. struct mbuf *tbp;
  175. struct ax_route *axr;
  176. char mode = AX_DEFMODE;    /* default to interface mode */
  177.  
  178.     if (gateway == iface->broadcast)    /* This is a broadcast IP datagram */
  179.         return (*iface->output) (iface, Ax25multi[0], iface->ipcall, PID_IP, bp);
  180.  
  181.     if ((hw_addr = res_arp (iface, ARP_AX25, gateway, bp)) == NULLCHAR)
  182.         return 0;    /* Wait for address resolution */
  183.  
  184.     /* If there's a defined route, get it */
  185.     axr = ax_lookup (NULLCHAR, hw_addr, iface, AX_NONSETUP);
  186.  
  187.     if (axr == NULLAXR) {
  188.         if (iface->flags & CONNECT_MODE)
  189.             mode = AX_VC_MODE;
  190.         else
  191.             mode = AX_DATMODE;
  192.     } else {
  193.         mode = axr->mode;
  194.         if (mode == AX_DEFMODE) {
  195.             if (iface->flags & CONNECT_MODE)
  196.                 mode = AX_VC_MODE;
  197.             else
  198.                 mode = AX_DATMODE;
  199.         }
  200.     }
  201.  
  202.     /* UI frames are used for any one of the following three conditions:
  203.      * 1. The "low delay" bit is set in the type-of-service field.
  204.      * 2. The "reliability" TOS bit is NOT set and the interface is in
  205.      *    datagram mode.
  206.      * 3. The destination is the broadcast address (this is helpful
  207.      *    when broadcasting on an interface that's in connected mode).
  208.      */
  209.     if (del || (!rel && (mode == AX_DATMODE)) || addreq (hw_addr, Ax25multi[0]))
  210.         /* Use UI frame */
  211.         return (*iface->output) (iface, hw_addr, iface->ipcall, PID_IP, bp);
  212.  
  213.     /* Reliability is needed; use I-frames in AX.25 connection */
  214.     if ((axp = find_ax25 (iface->ipcall, hw_addr, iface)) == NULLAX25) {
  215.         /* Open a new connection */
  216.         axp = open_ax25 (iface, iface->ipcall, hw_addr,
  217.              AX_ACTIVE, Axwindow, s_arcall, s_atcall, s_ascall, -1);
  218.         if (axp == NULLAX25) {
  219.             free_p (bp);
  220.             return -1;
  221.         }
  222.     }
  223.     if (axp->state == LAPB_DISCONNECTED) {
  224.         est_link (axp);
  225.         lapbstate (axp, LAPB_SETUP);
  226.     }
  227.     /* Insert the PID */
  228.     if ((tbp = pushdown (bp, 1)) == NULLBUF) {
  229.         free_p (bp);
  230.         return -1;
  231.     }
  232.     bp = tbp;
  233.     bp->data[0] = PID_IP;
  234.     if ((tbp = segmenter (bp, axp->paclen, axp)) == NULLBUF) {
  235.         free_p (bp);
  236.         return -1;
  237.     }
  238.     return send_ax25 (axp, tbp, -1);
  239. }
  240.  
  241.  
  242.  
  243. /* Add header and send connectionless (UI) AX.25 packet.
  244.  * Note that the calling order here must match enet_output
  245.  * since ARP also uses it.
  246.  */
  247. int
  248. ax_output (iface, dest, source, pid, data)
  249. struct iface *iface;        /* Interface to use; overrides routing table */
  250. const char *dest;        /* Destination AX.25 address (7 bytes, shifted) */
  251. char *source;            /* Source AX.25 address (7 bytes, shifted) */
  252. int16 pid;            /* Protocol ID */
  253. struct mbuf *data;        /* Data field (follows PID) */
  254. {
  255. struct mbuf *bp;
  256. int retval;
  257.  
  258.     /* Prepend pid to data */
  259.     bp = pushdown (data, 1);
  260.     if (bp == NULLBUF) {
  261.         free_p (data);
  262.         return -1;
  263.     }
  264.     bp->data[0] = uchar(pid);
  265.  
  266.     retval = axsend (iface, dest, source, LAPB_COMMAND, UI, bp);
  267.  
  268.     /* update the counters for messages out */
  269.     if (retval != -1)
  270.         incCounter (iface);
  271.  
  272.     return retval;
  273. }
  274.  
  275.  
  276.  
  277. /* Common subroutine for sendframe() and ax_output() */
  278. static int
  279. axsend (iface, dest, source, cmdrsp, ctl, data)
  280. struct iface *iface;        /* Interface to use; overrides routing table */
  281. const char *dest;        /* Destination AX.25 address (7 bytes, shifted) */
  282. char *source;            /* Source AX.25 address (7 bytes, shifted) */
  283. int cmdrsp;            /* Command/response indication */
  284. int ctl;            /* Control field */
  285. struct mbuf *data;        /* Data field (includes PID) */
  286. {
  287. struct mbuf *cbp;
  288. struct ax25 addr;
  289. struct ax_route *axr;
  290. char const *idest;
  291. int rval;
  292.  
  293.     /* If the source addr is unspecified, use the interface address */
  294.     if (source[0] == '\0')
  295.         source = iface->hwaddr;
  296.  
  297.     /* If there's a digipeater route, get it */
  298.     axr = ax_lookup (source, dest, iface, AX_NONSETUP);
  299.  
  300.     memcpy (addr.dest, dest, AXALEN);
  301.     memcpy (addr.source, source, AXALEN);
  302.     addr.cmdrsp = cmdrsp;
  303.  
  304.     if (axr != NULLAXR) {
  305.         memcpy (addr.digis, axr->digis, (size_t) axr->ndigis * AXALEN);
  306.         addr.ndigis = axr->ndigis;
  307.         idest = addr.digis[0];
  308.     } else {
  309.         addr.ndigis = 0;
  310.         idest = dest;
  311.     }
  312.  
  313.     addr.nextdigi = 0;
  314.  
  315.     /* Allocate mbuf for control field, and fill in */
  316.     if ((cbp = pushdown (data, 1)) == NULLBUF) {
  317.         free_p (data);
  318.         return -1;
  319.     }
  320.     cbp->data[0] = uchar(ctl);
  321.  
  322.     if ((data = htonax25 (&addr, cbp)) == NULLBUF) {
  323.         free_p (cbp);    /* Also frees data */
  324.         return -1;
  325.     }
  326.  
  327.     /* This shouldn't be necessary because redirection has already been
  328.      * done at the IP router layer, but just to be safe...
  329.      */
  330.     if (iface->forw != NULLIF) {
  331. #ifdef notdef
  332.         logsrc (iface->forw, iface->forw->hwaddr);
  333. #endif
  334.         logsrc (iface->forw, source);
  335.         logdest (iface->forw, idest);
  336.         rval = (*iface->forw->raw) (iface->forw, data);
  337.     } else {
  338. #ifdef notdef
  339.         logsrc (iface, iface->hwaddr);
  340. #endif
  341.         logsrc (iface, source);
  342.         logdest (iface, idest);
  343.         rval = (*iface->raw) (iface, data);
  344.     }
  345.     return rval;
  346. }
  347.  
  348.  
  349.  
  350. #ifdef    AXIP
  351. /* Handle AX.25 frames received inside IP according to RFC-1226 */
  352. void
  353. axip_input (iface, ip, bp, rxbroadcast)
  354. struct iface *iface;        /* Input interface */
  355. struct ip *ip;            /* IP header */
  356. struct mbuf *bp;        /* AX.25 frame with FCS */
  357. int rxbroadcast OPTIONAL;    /* Accepted for now */
  358. {
  359. int i;
  360. struct mbuf *tbp;
  361. int16 len, f, fcs = 0xffff;
  362. #ifdef RXECHO
  363. struct mbuf *bbp;
  364. #endif
  365.  
  366.     /* Since the AX.25 frame arrived on an interface that does
  367.        not necessarily support AX.25, we have to find a suitable
  368.        AX.25 interface, or drop the packet.
  369.      */
  370.     /* Try to find a matching AX.25 pseudo interface */
  371.     for (i = 0; i < AXIPlinks; ++i)
  372.         if (axipaddr[i] == ip->source)
  373.             break;
  374.     if (i == AXIPlinks) {
  375.         /* Here we could still try to pick a real AX.25 interface,
  376.            but that would mean that we are accepting AX.25 frames
  377.            from unknown IP hosts, so we'd rather drop it.
  378.          */
  379.         free_p (bp);
  380.         return;
  381.     }
  382.     iface = Ifaces;
  383.     while (iface != NULLIF) {
  384.         if (iface->raw == axip_raw && iface->dev == i)
  385.             /* found the right AX.25 pseudo interface */
  386.             break;
  387.         iface = iface->next;
  388.     }
  389.     if (iface == NULLIF) {
  390.         free_p (bp);
  391.         return;
  392.     }
  393.     len = len_p (bp) - sizeof (fcs);
  394.     if (dup_p (&tbp, bp, 0, len) != len) {
  395.         free_p (bp);
  396.         return;
  397.     }
  398.     while (len--)
  399.         fcs = (fcs >> 8) ^ fcstab[(fcs ^ PULLCHAR (&bp)) & 0x00ff];    /*lint !e506 */
  400.     fcs ^= 0xffff;
  401.     f = (int16) PULLCHAR (&bp);        /*lint !e506 */
  402.     f |= (int16) (PULLCHAR (&bp) << 8);    /*lint !e506 !e701 */
  403.     if (fcs == f) {
  404.         /* add some tracing - WG7J */
  405. #ifdef TRACE
  406.         dump (iface, IF_TRACE_IN, CL_AX25, tbp);
  407. #endif
  408. #ifdef RXECHO
  409.         /* If configured, echo this packet before handling - WG7J */
  410.         if (iface && iface->rxecho) {
  411.             (void) dup_p (&bbp, tbp, 0, len_p (tbp));    /* as it was */
  412.             (void) (*iface->rxecho->raw) (iface->rxecho, bbp);
  413.         }
  414. #endif
  415.         ax_recv (iface, tbp);
  416.     } else
  417.         free_p (tbp);
  418. }
  419. #endif
  420.  
  421.  
  422.  
  423. /* Process incoming AX.25 packets.
  424.  * After optional tracing, the address field is examined. If it is
  425.  * directed to us as a digipeater, repeat it.  If it is addressed to
  426.  * us or to QST-0, kick it upstairs depending on the protocol ID.
  427.  */
  428. extern int32 CT4init;
  429.  
  430.  
  431.  
  432. void
  433. ax_recv (struct iface *iface, struct mbuf *bp)
  434. {
  435. struct mbuf *hbp;
  436. unsigned char control;
  437. struct ax25 hdr;
  438. struct ax25_cb *axp = NULLAX25;
  439. struct ax_route *axr;
  440. struct iface *cross;
  441. int nomark = 0;
  442. char (*mpp)[AXALEN];
  443. int mcast;
  444. char *isrc, *idest;    /* "immediate" source and destination */
  445. int To_us = 0;        /* Is this a link to us ? */
  446. int send2axui = 0;
  447.  
  448.     /* Pull header off packet and convert to host structure */
  449.     if (ntohax25 (&hdr, &bp) < 0) {
  450.         /* Something wrong with the header */
  451.         free_p (bp);
  452.         return;
  453.     }
  454. #ifdef AUTOROUTE
  455.     /* Check that there are no illegal characters in the header.  If there
  456.        are, then this packet is corrupt.
  457.        To ease maintainability, put this code in ax25aar.c, where the
  458.        autoreverse IP routing code is situated.
  459.  
  460.        G4JEC  15 December 1990.
  461.      */
  462.     if (ax25_check_corruption (&hdr)) {    /* If returned integer is set, then the packet is corrupt. Free the packet. */
  463.         free_p (bp);
  464.         return;
  465.     }
  466. #endif /* AUTOROUTE */
  467.  
  468.     if (iface->flags & LOG_IPHEARD) {
  469.         struct mbuf *nbp;
  470.         struct ip ip;
  471.         int len;
  472.  
  473.         len = len_p (bp);
  474.         if (dup_p (&nbp, bp, 0, (int16) len) == len) {
  475.             /* find higher proto, if any */
  476.             (void) PULLCHAR (&nbp);        /*lint !e506 * skip control byte */
  477.             if (PULLCHAR (&nbp) == PID_IP) {    /*lint !e506 */
  478.                 (void) ntohip (&ip, &nbp);
  479.                 if (ip.version == IPVERSION)
  480.                     log_ipheard (ip.source, iface);
  481.             }
  482.             free_p (nbp);
  483.         }
  484.     }
  485.     /* If there were digis in this packet and at least one has
  486.      * been passed, then the last passed digi is the immediate source.
  487.      * Otherwise it is the original source.
  488.      */
  489.     if (hdr.ndigis != 0 && hdr.nextdigi != 0)
  490.         isrc = hdr.digis[hdr.nextdigi - 1];
  491.     else
  492.         isrc = hdr.source;
  493.  
  494.     /* If there are digis in this packet and not all have been passed,
  495.      * then the immediate destination is the next digi. Otherwise it
  496.      * is the final destination.
  497.      */
  498.     cross = NULLIF;
  499.     if (hdr.ndigis != 0 && hdr.nextdigi != hdr.ndigis) {
  500.         idest = hdr.digis[hdr.nextdigi];
  501.         if (!addreq (idest, iface->hwaddr)) {
  502.             /* Check if digi matches callsign of any other
  503.              * interface for crossband digipeating.
  504.              */
  505.             for (cross = Ifaces; cross != NULLIF; cross = cross->next) {
  506.                 if (cross->type == CL_AX25 && addreq (idest, cross->hwaddr)) {
  507.                     /* Swap callsigns so that the reply
  508.                      * can be crossband digipeated in
  509.                      * the other direction.
  510.                      */
  511.                     memcpy (idest, iface->hwaddr, AXALEN);
  512.                     break;
  513.                 }
  514.             }
  515.         }
  516.     } else
  517.         idest = hdr.dest;
  518.  
  519.     /* Don't log our own packets if we overhear them, as they're
  520.      * already logged by axsend() and by the digipeater code.
  521.      */
  522.     if (!addreq (isrc, iface->hwaddr) && !addreq (isrc, iface->ipcall)) {
  523.  
  524. #ifdef NETROM
  525.         if (Nr_iface == NULLIF || !addreq (isrc, Nr_iface->hwaddr)) {
  526. #endif
  527.             logsrc (iface, isrc);
  528.             logdest (iface, idest);
  529. #ifdef NETROM
  530.         }
  531. #endif
  532.     }
  533.     /* Examine immediate destination for a multicast address */
  534.     mcast = 0;
  535.     for (mpp = Ax25multi; (*mpp)[0] != '\0'; mpp++) {
  536.         if (addreq (idest, *mpp)) {
  537.             mcast = 1;
  538.             break;
  539.         }
  540.     }
  541.  
  542.  
  543.     /* Now check for any connection already in the AX.25 cb list
  544.      * This allows netrom user connects (with inverted ssid's) ,
  545.      * connections already established etc.. to pass.
  546.      * There should be no more digis needed!
  547.      * Added 11/15/91 WG7J
  548.      */
  549.     if (hdr.nextdigi == hdr.ndigis)
  550.         /* See if the source and destination address are in hash table */
  551.         if ((axp = find_ax25 (hdr.dest, hdr.source, iface)) != NULLAX25)
  552.             To_us = KNOWN_LINK;
  553.  
  554.     /* Check to see if this is the Netrom interface callsign
  555.      * or the alias ! Accept any SSID on the alias.
  556.      * NOTE: This also allows digipeating via those calls!
  557.      * Added 11/15/91 WG7J
  558.      */
  559.     if (!To_us) {
  560. #ifdef NETROM
  561.         if (addreq (idest, Myalias))
  562.             To_us =
  563. #ifdef NODECALL
  564.                 (NodeAlias) ? NODE_LINK :
  565. #endif
  566.                 ALIAS_LINK;    /* this is for the alias */
  567.         else if ((iface->flags & IS_NR_IFACE) && addreq (idest, Nr_iface->hwaddr))
  568.             To_us =
  569. #ifdef NODECALL
  570.                 (NodeNetrom) ? NODE_LINK :
  571. #endif
  572.                 NETROM_LINK;    /* this is for the netrom callsign! */
  573.         else
  574. #endif
  575.         if (addreq (idest, iface->hwaddr))
  576.             To_us = IFACE_LINK;    /* this is to the interface call */
  577. #ifdef CONVERS
  578.         else if (addreq (hdr.dest, Ccall) && (iface->flags & IS_CONV_IFACE))
  579.             To_us = CONF_LINK;    /* this is for the conference call */
  580.         else if (addreq (hdr.dest, Calias) && (iface->flags & IS_CONV_IFACE))
  581.             To_us = CONF_LINK;    /* this is for the conference alias */
  582. #endif
  583. #ifdef TUTOR
  584.         else if (addreq (hdr.dest, Tcall))
  585.             To_us = TUTOR_LINK;    /* this is for the tutor server call */
  586.         else if (addreq (hdr.dest, Icall))
  587.             To_us = INFO_LINK;    /* this is for the info server call */
  588.         else if (addreq (hdr.dest, Ncall))
  589.             To_us = NEWS_LINK;    /* this is for the news server call */
  590. #endif
  591. #ifdef NODECALL
  592.         else if (addreq (hdr.dest, Nodecall))
  593.             To_us = NODE_LINK;    /* this is for the news server call */
  594.         else if (addreq (hdr.dest, Nodealias))
  595.             To_us = NODE_LINK;    /* this is for the news server call */
  596. #endif
  597. #ifdef TTYCALL
  598.         else if (addreq (idest, Ttycall))
  599.             To_us = TTY_LINK;
  600. #endif
  601.         else if (addreq (idest, MyBBS))
  602.             To_us = ALIAS_LINK;
  603.         else if (addreq (idest, Mycall))
  604.             To_us = IFACE_LINK;
  605. #ifdef MBFWD
  606.         else if (addreq (idest, FWDCall))
  607.             To_us = IFACE_LINK;
  608. #endif
  609.     }
  610.     if (addreq (idest, iface->ipcall)) {
  611.         To_us |= IP_LINK;
  612.         if (To_us & KNOWN_LINK && axp != NULLAX25)
  613.             axp->jumpstarted = To_us;
  614.     }
  615.     if (AXSmartRoute && !To_us && !mcast && !cross) {
  616.         nomark = 1;
  617.         for (cross = Ifaces; cross != NULLIF; cross = cross->next) {
  618.             if (iface == cross)    /* skip same interface */
  619.                 continue;
  620.             if (cross->type == CL_AX25) {
  621.                 /* this one checks to see if it is an axip dstaddr */
  622.                 if (cross->rmtaddr && (addreq (hdr.dest, cross->rmtaddr) || addreq (idest, cross->rmtaddr)))
  623.                     break;
  624.  
  625.                 /* this one handles a neighbor in dest if no digis or all digis done */
  626.                 if ((!hdr.ndigis || (hdr.nextdigi == hdr.ndigis)) && ((ax_lookup (NULLCHAR, hdr.dest, cross, AX_NONSETUP) != NULLAXR) || ad_lookup (cross, hdr.dest, 1)))
  627.                     break;
  628.  
  629.                 /* this one handles a neighbor in the digi list as the next digi */
  630.                 if (ax_lookup (NULLCHAR, idest, cross, AX_NONSETUP) != NULLAXR || al_lookup (cross, idest, 1))
  631.                     break;
  632.             }
  633.         }
  634.         nomark = (int) cross;    /* if not found here, then == 0 */
  635.     }
  636. #ifdef AXUI        /* K5JB: for axui, mustn't discard other UI frames */
  637.     if (Axui_sock != -1 && !mcast) {    /* UI Session active? */
  638.         control = *bp->data & ~PF;
  639.         if (control == UI)
  640.             send2axui = 1;    /* will fake it */
  641.     }
  642. #endif
  643.  
  644.     if (!To_us && !mcast && !cross) {
  645.         /* Not a broadcast, and not addressed to us. Inhibit
  646.          * transmitter to avoid colliding with addressed station's
  647.          * response, and discard packet.
  648.          */
  649. #ifdef notdef
  650.         if (iface->ioctl != NULL) {
  651.             (*iface->ioctl) (iface, PARAM_MUTE, 1, -1L);
  652.         }
  653. #endif
  654.         free_p (bp);
  655.         return;
  656.     }
  657. #ifdef notdef
  658.     if (!mcast && !cross && iface->ioctl != NULL) {
  659.         /* Packet was sent to us; abort transmit inhibit */
  660.         (*iface->ioctl) (iface, PARAM_MUTE, 1, 0L);
  661.     }
  662. #endif
  663.     /* At this point, packet is either addressed to us, or is
  664.      * a multicast.
  665.      */
  666.     if (addreq (hdr.source, NOCALL)) {    /* don't even acknowledge NOCALL's */
  667.         free_p (bp);
  668.         return;
  669.     }
  670.     if (nomark || hdr.nextdigi < hdr.ndigis) {    /* Packet requests digipeating. See if we can repeat it. */
  671.         if ((iface->flags & AX25_DIGI) && !mcast) {
  672.             /* Yes, kick it back out. htonax25 will set the
  673.              * repeated bit.
  674.              */
  675.             if (!nomark)
  676.                 hdr.nextdigi++;
  677.  
  678.             if (cross)    /* Crossband digipeat */
  679.                 iface = cross;
  680.             if (iface->flags & AX25_DIGI) {
  681.                 if ((hbp = htonax25 (&hdr, bp)) != NULLBUF) {
  682.                     logsrc (iface, iface->hwaddr);
  683.                     if (iface->forw != NULLIF) {
  684.                         logdest (iface->forw, hdr.digis[hdr.nextdigi]);
  685.                         (void) (*iface->forw->raw) (iface->forw, hbp);
  686.                     } else {
  687.                         logdest (iface, hdr.digis[hdr.nextdigi]);
  688.                         (void) (*iface->raw) (iface, hbp);
  689.                     }
  690.                     bp = NULLBUF;
  691.                 }
  692.             }
  693.         }
  694. #ifdef AXUI
  695.         axui_input (iface, NULLAX25, hdr.source, hdr.dest, bp, (mcast + send2axui));
  696. #else
  697.         free_p (bp);    /* Dispose if not forwarded */
  698. #endif
  699.         return;
  700.     }
  701.     /* If we reach this point, then the packet has passed all digis,
  702.      * and is either addressed to us or is a multicast
  703.      */
  704.     if (bp == NULLBUF)
  705.         return;        /* Nothing left */
  706.  
  707.     /* If there's no locally-set entry in the routing table and
  708.      * this packet has digipeaters, create or update it. Leave
  709.      * local routes alone.
  710.      */
  711.     if (((axr = ax_lookup (NULLCHAR, hdr.source, iface, AX_NONSETUP)) == NULLAXR || axr->type == AX_AUTO) && hdr.ndigis > 0) {
  712.         char digis[MAXDIGIS][AXALEN];
  713.         int i, j;
  714.  
  715.         /* Construct reverse digipeater path */
  716.         for (i = hdr.ndigis - 1, j = 0; i >= 0; i--, j++) {
  717.             memcpy (digis[j], hdr.digis[i], AXALEN);
  718.             digis[j][ALEN] &= (char)(~(E | REPEATED));
  719.         }
  720.         (void) ax_add (hdr.source, AX_AUTO, digis, hdr.ndigis, iface);
  721.     }
  722.     /* Sneak a peek at the control field. This kludge is necessary because
  723.      * AX.25 lacks a proper protocol ID field between the address and LAPB
  724.      * sublayers; a control value of UI indicates that LAPB is to be
  725.      * bypassed.
  726.      */
  727.     control = (*bp->data & ~PF);
  728.  
  729.     if (control == UI) {
  730.         int pid;
  731.         struct axlink *ipp;
  732.  
  733.         (void) PULLCHAR (&bp);            /*lint !e506 */
  734.         if ((pid = PULLCHAR (&bp)) == -1)    /*lint !e506 */
  735.             return;    /* No PID */
  736.         /* Find network level protocol and hand it off */
  737.         for (ipp = Axlink; ipp->funct != NULL; ipp++) {
  738.             if (ipp->pid == pid)
  739.                 break;
  740.         }
  741.         if (ipp->funct != NULL)
  742.             (*ipp->funct) (iface, NULLAX25, hdr.source, hdr.dest, bp, (mcast + send2axui));
  743.         else
  744.             free_p (bp);
  745.         return;
  746.     }
  747.     /* Everything from here down is connected-mode LAPB, so ignore
  748.      * multicasts
  749.      */
  750.     if ((mcast + send2axui) != 0) {
  751.         free_p (bp);
  752.         return;
  753.     }
  754.     /* At this point, if we already have a connection on its way,
  755.      * we already have found the control block !
  756.      * 11/15/91 WG7J/PA3DIS
  757.      */
  758.     if (!(To_us & KNOWN_LINK)) {
  759.         /* This is a new connection to either the interface call,
  760.          * or to the BBS call or the BBS alias or the INFO call
  761.          * or the NEWS call or the TUTOR call or the IPCALL,
  762.          * or to the netrom-interface call or system alias.
  763.          * Create a new ax25 entry for this guy,
  764.          * insert into hash table keyed on his address,
  765.          * and initialize table entries
  766.          */
  767.         if ((axp = cr_ax25 (hdr.dest, hdr.source, iface)) == NULLAX25) {
  768.             free_p (bp);
  769.             return;
  770.         }
  771. #if 1
  772.         /* add route to newly created connection block */
  773.         axp->route = (struct ax_route *) callocw (1, sizeof (struct ax_route));
  774.         hdr.source[AXALEN - 1] &= SSID;
  775.         memcpy (axp->route->target, hdr.source, AXALEN);
  776.         axp->route->ndigis = hdr.ndigis;
  777.         axp->route->iface = iface;
  778.         axp->route->mode = AX_DEFMODE;    /* set mode to default */
  779.         {
  780.         int i, j;
  781.             
  782.             for (i = hdr.ndigis - 1, j = 0; i >= 0; i--, j++) {
  783.                 memcpy (axp->route->digis[j], hdr.digis[i], AXALEN);
  784.                 axp->route->digis[j][ALEN] &= (char)(~(E | REPEATED));
  785.             }
  786.         }
  787. #endif
  788. #ifdef CONVERS
  789.         /* set a different T4 if conference link - WG7J */
  790.         if (To_us == CONF_LINK)
  791.             set_timer (&axp->t4, CT4init * 1000L);
  792. #endif
  793.         axp->jumpstarted = To_us;
  794.         if (hdr.cmdrsp == LAPB_UNKNOWN)
  795.             axp->proto = V1;    /* Old protocol in use */
  796.     }
  797.     (void) lapb_input (axp, hdr.cmdrsp, bp);
  798. }
  799.  
  800.  
  801.  
  802. /* General purpose AX.25 frame output */
  803. int
  804. sendframe (struct ax25_cb *axp, int cmdrsp, int ctl, struct mbuf *data)
  805. {
  806. int retval;
  807.  
  808.     retval = axsend (axp->iface, axp->remote, axp->local, cmdrsp, ctl, data);
  809.  
  810.     /* update the counters for messages out */
  811.     if (retval != -1)
  812.         incCounter(axp->iface);
  813.  
  814.     return retval;
  815. }
  816.  
  817.  
  818.  
  819. /* Find a route for an AX.25 address
  820.  * Code to remove SSID field C/R- and E-bits in ax_lookup(), ax_add() and
  821.  * ax_drop() added by vk6zjm 4/5/92. This eliminates duplicate AX25 routes.
  822.  * 1992-05-28 - Added interface -- sm6rpz
  823.  */
  824.  
  825. struct ax_route *
  826. ax_lookup (const char *source, const char *target, struct iface *ifp, int type)
  827. {
  828. register struct ax_route *axr;
  829. struct ax_route **routetbl = &Ax_routes;
  830. struct ax_route *axlast = NULLAXR;
  831. char xtarget[AXALEN];
  832. char xsource[AXALEN];
  833. struct ax25_cb *axp;
  834. int onlysetup = 0;
  835.  
  836.     if (type == AX_SETUP)
  837.         routetbl = &Ax_setups;
  838.  
  839.     /* Remove C/R and E bits in local copy only */
  840.     memcpy (xtarget, target, AXALEN);
  841.     xtarget[AXALEN - 1] &= SSID;
  842.  
  843.     if (source == (char *)-1)    {
  844.         onlysetup = 1;
  845.         source = NULLCHAR;
  846.     }
  847.  
  848.     /* if source address is present, then we set it up too, then
  849.        see if this is part of an active connection. If so, we return
  850.        the digis used to set up the connection, instead of the current
  851.        ones */
  852.     if (source)    {
  853.         /* Remove C/R and E bits in local copy only */
  854.         memcpy (xsource, source, AXALEN);
  855.         xsource[AXALEN - 1] &= SSID;
  856.         if ((axp = find_ax25 (source, target, ifp)) != NULLAX25)
  857.             return axp->route;
  858.     }
  859.        
  860.     do    {
  861.         for (axr = *routetbl; axr != NULLAXR; axlast = axr, axr = axr->next) {
  862.             if (addreq (axr->target, xtarget) && axr->iface == ifp) {
  863.                 if (axr != *routetbl && axlast != NULLAXR) {
  864.                     /* Move entry to top of list to speed
  865.                      * future searches
  866.                      */
  867.                     axlast->next = axr->next;
  868.                     axr->next = *routetbl;
  869.                     *routetbl = axr;
  870.  
  871.                 }
  872.                 return axr;
  873.             }
  874.         }
  875.         if (routetbl == &Ax_setups && !onlysetup)
  876.             routetbl = &Ax_routes;
  877.         else
  878.             routetbl = (struct ax_route **)0;
  879.     } while (routetbl != (struct ax_route **)0);
  880.     return axr;
  881. }
  882.  
  883.  
  884.  
  885. /* Add an entry to the AX.25 routing table */
  886. struct ax_route *
  887. ax_add (char *target, int type, char digis[][AXALEN], int ndigis, struct iface *ifp)
  888. {
  889. register struct ax_route *axr;
  890. struct ax_route **routetbl = &Ax_routes;
  891. char xtarget[AXALEN];
  892.  
  893.     if (ndigis < 0 || ndigis > MAXDIGIS || addreq (target, ifp->hwaddr) || addreq (target, ifp->ipcall))
  894.         return NULLAXR;
  895.  
  896.     if (type == AX_SETUP)
  897.         routetbl = &Ax_setups;
  898.  
  899.     /* Remove C/R and E bits in local copy only */
  900.     memcpy (xtarget, target, AXALEN);
  901.     xtarget[AXALEN - 1] &= SSID;
  902.  
  903.     if ((axr = ax_lookup ((char *)-1, xtarget, ifp, type)) == NULLAXR) {
  904.         axr = (struct ax_route *) callocw (1, sizeof (struct ax_route));
  905.  
  906.         axr->next = *routetbl;
  907.         *routetbl = axr;
  908.         memcpy (axr->target, xtarget, AXALEN);
  909.         axr->ndigis = ndigis;
  910.         axr->iface = ifp;
  911.         axr->mode = AX_DEFMODE;    /* set mode to default */
  912.         if (type == AX_SETUP)
  913.             Ax_setups_counter = 1100;
  914.     } else
  915.         /* don't allow an AUTO to override a LOCAL entry */
  916.         if ((axr->type == AX_LOCAL) && (type == AX_AUTO))
  917.             return axr;
  918.  
  919.     axr->type = (char) type;
  920.     if (axr->ndigis != ndigis)
  921.         axr->ndigis = ndigis;
  922.  
  923.     memcpy (axr->digis, digis[0], (size_t) ndigis * AXALEN);
  924.     return axr;
  925. }
  926.  
  927.  
  928.  
  929. int
  930. ax_drop (char *target, struct iface *ifp, int type)
  931. {
  932. struct ax_route **routetbl = &Ax_routes;
  933. register struct ax_route *axr;
  934. struct ax_route *axlast = NULLAXR;
  935. char xtarget[AXALEN];
  936.  
  937.     if (type == AX_SETUP)
  938.         routetbl = &Ax_setups;
  939.  
  940.     /* Remove C/R and E bits in local copy only */
  941.     memcpy (xtarget, target, AXALEN);
  942.     xtarget[AXALEN - 1] &= SSID;
  943.  
  944.     for (axr = *routetbl; axr != NULLAXR; axlast = axr, axr = axr->next)
  945.         if (addreq (axr->target, xtarget) && axr->iface == ifp)
  946.             break;
  947.     if (axr == NULLAXR)
  948.         return -1;    /* Not in table! */
  949.     if (axlast != NULLAXR)
  950.         axlast->next = axr->next;
  951.     else
  952.         *routetbl = axr->next;
  953.  
  954.     free ((char *) axr);
  955.     return 0;
  956. }
  957.  
  958.  
  959.  
  960. /* This function gets called every clock tick, to elegantly remove
  961.    stale ax25 route in the Ax_setups queue */
  962. void
  963. axsetupflush (void)
  964. {
  965. struct ax_route *axr, *next = NULLAXR;
  966.  
  967.     if (Ax_setups_counter)    {
  968.         if (--Ax_setups_counter == 0)    {
  969.             for (axr = Ax_setups; axr != NULLAXR; axr = next)    {
  970.                 next = axr->next;
  971.                 free (axr);
  972.             }
  973.             Ax_setups = NULLAXR;
  974.         }
  975.     }
  976. }
  977.  
  978.  
  979. /* Handle ordinary incoming data (no network protocol) */
  980. void
  981. axnl3 (struct iface *iface OPTIONAL, struct ax25_cb *axp, char *src OPTIONAL,
  982.     char *dest OPTIONAL, struct mbuf *bp, int mcast OPTIONAL)
  983. {
  984.     if (axp == NULLAX25) {
  985. #ifdef AXUI
  986.         axui_input (iface, axp, src, dest, bp, mcast);
  987. #else
  988.         /* beac_input(iface,src,bp); */
  989.         free_p (bp);
  990. #endif
  991.     } else {
  992.         append (&axp->rxq, bp);
  993.         if (axp->r_upcall != NULLVFP ((struct ax25_cb *, int)))
  994.             (*axp->r_upcall) (axp, len_p (axp->rxq));
  995.     }
  996. }
  997.  
  998.  
  999.  
  1000. #ifdef    AXIP
  1001. /* attach a fake AX.25 interface for AX.25 on top of IP */
  1002. /* argv[0] == "axip"
  1003.  * argv[1] == name of new interface
  1004.  * argv[2] == MTU
  1005.  * argv[3] == hostname of remote end of wormhole
  1006.  * argv[4] == optional AX.25 callsign for this interface, must be specified
  1007.  *          and be different from any other interface callsign if crossband
  1008.  *             digipeating is going to work properly
  1009.  * argv[5] == optional AX.25 callsign for the remote end of this interface
  1010.  *            used only by the smart routing, at this time
  1011.  */
  1012. int
  1013. axip_attach (int argc, char *argv[], void *p OPTIONAL)
  1014. {
  1015. int i;
  1016. struct iface *ifp;
  1017.  
  1018.     /* Check for too long iface names - WG7J */
  1019.     if (strlen (argv[1]) >= ILEN) {
  1020.         tprintf ("interface max %d chars\n", ILEN - 1);
  1021.         return -1;
  1022.     }
  1023.     if (if_lookup (argv[1]) != NULLIF) {
  1024.         tprintf ("interface %s already attached\n", argv[1]);
  1025.         return -1;
  1026.     }
  1027.     for (i = 0; i < AXIPlinks; ++i)
  1028.         if (axipaddr[i] == 0)
  1029.             break;
  1030.     if (i == AXIPlinks) {
  1031.         tputs ("too many AX25 interfaces attached\n");
  1032.         return -1;
  1033.     }
  1034.     if ((axipaddr[i] = resolve (argv[3])) == 0) {
  1035.         tputs ("invalid address\n");
  1036.         return -1;
  1037.     }
  1038.     ifp = (struct iface *) callocw (1, sizeof (struct iface));
  1039.  
  1040.     ifp->dev = i;
  1041.     ifp->addr = Ip_addr;
  1042.     ifp->name = strdup (argv[1]);
  1043.     ifp->iface_metric = 1;
  1044.     ifp->hwaddr = mallocw (AXALEN);
  1045.     memcpy (ifp->hwaddr, Mycall, AXALEN);
  1046.     ifp->ipcall = mallocw (AXALEN);
  1047.     memcpy (ifp->ipcall, Mycall, AXALEN);
  1048.     ifp->mtu = (int16) atoi (argv[2]);
  1049.     (void) setencap (ifp, "AX25");
  1050.     if (argc > 4) {
  1051.         free (ifp->hwaddr);
  1052.         free (ifp->ipcall);
  1053.         ifp->hwaddr = mallocw ((unsigned) ifp->iftype->hwalen);
  1054.         (void) (*ifp->iftype->scan) (ifp->hwaddr, argv[4]);
  1055.         ifp->ipcall = mallocw ((unsigned) ifp->iftype->hwalen);
  1056.         (void) (*ifp->iftype->scan) (ifp->ipcall, argv[4]);
  1057.     }
  1058.     if (argc > 5) {
  1059.         ifp->rmtaddr = mallocw ((unsigned) ifp->iftype->hwalen);
  1060.         (void) (*ifp->iftype->scan) (ifp->rmtaddr, argv[5]);
  1061.     }
  1062.     ifp->raw = axip_raw;
  1063.     ifp->stop = axip_stop;
  1064.     ifp->next = Ifaces;
  1065.     Ifaces = ifp;
  1066.     return 0;
  1067. }
  1068.  
  1069.  
  1070.  
  1071. static int
  1072. axip_stop (struct iface *iface)
  1073. {
  1074.     axipaddr[iface->dev] = 0;
  1075.     return 0;
  1076. }
  1077.  
  1078.  
  1079.  
  1080. /* raw routine for sending AX.25 on top of IP */
  1081. static int
  1082. axip_raw (iface, bp)
  1083. struct iface *iface;        /* Pointer to interface control block */
  1084. struct mbuf *bp;        /* Data field */
  1085. {
  1086. int16 len, fcs = 0xffff;
  1087. struct mbuf *bp1;
  1088.  
  1089.     dump (iface, IF_TRACE_OUT, (unsigned) iface->type, bp);
  1090.     iface->rawsndcnt++;
  1091.     iface->lastsent = secclock ();
  1092.     len = len_p (bp);
  1093.     if (dup_p (&bp1, bp, 0, len) != len) {
  1094.         free_p (bp);
  1095.         return -1;
  1096.     }
  1097.     while (len--)        /* calculate FCS */
  1098.         fcs = (fcs >> 8) ^ fcstab[(fcs ^ PULLCHAR (&bp1)) & 0x00ff];    /*lint !e506 */
  1099.  
  1100.     fcs ^= 0xffff;        /* final FCS (is this right?) */
  1101.     if ((bp1 = alloc_mbuf (sizeof (fcs))) == NULLBUF) {
  1102.         free_p (bp);
  1103.         return -1;
  1104.     }
  1105.     *bp1->data = fcs & 0xff;
  1106.     *(bp1->data + 1) = (fcs >> 8) & 0xff;
  1107.     bp1->cnt += sizeof (fcs);
  1108.     append (&bp, bp1);
  1109.     return ip_send (INADDR_ANY, axipaddr[iface->dev], AX25_PTCL, 0, 0, bp, 0, 0, 0);
  1110. }
  1111.  
  1112. #endif
  1113.  
  1114. #endif /* AX25 */
  1115.